/*
 * Copyright (c) 2018 Hitevision
 *
 * Original class by Jaeger, chjie.jaeger@gmail.com
 */

package tw.com.hitevision.whiteboard.android.util;

import android.app.Activity;
import android.content.Context;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.Rect;
import android.text.Layout;
import android.text.StaticLayout;
import android.text.TextPaint;
import android.util.DisplayMetrics;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewTreeObserver;
import android.view.inputmethod.InputMethodManager;
import android.widget.TextView;

public class TextLayoutUtil {

    private static Matrix mat;
    private static Rect rect;

    public static int getScreenWidth(Context context) {
        return context.getResources().getDisplayMetrics().widthPixels;
    }

    public static void getCursorByEvent(TextView textBox, MotionEvent event, boolean eventFromParent, OngetCursorLis lis) {
        getCursorByEvent(textBox, event.getX(), event.getY(), eventFromParent, lis);
    }

    public static interface OngetCursorLis {
        public void onGetCursor(int cur);
    }

    public static void getCursorByEvent(TextView textBox, float eventX, float eventY, boolean eventFromParent, OngetCursorLis lis) {

        if (textBox == null) {
            return;
        }

        Layout layout = textBox.getLayout();

        if (layout == null) {
            ViewTreeObserver observer = textBox.getViewTreeObserver();
            observer.addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
                Layout layout;

                @Override
                public void onGlobalLayout() {
                    layout = textBox.getLayout();
                    int offset;

                    offset = getCursorByPosition(textBox, layout, eventX, eventY, eventFromParent);

                    lis.onGetCursor(offset);

                    observer.removeOnGlobalLayoutListener(this);
                }
            });

        } else {
            int offset;

            offset = getCursorByPosition(textBox, layout, eventX, eventY, eventFromParent);

            lis.onGetCursor(offset);
        }

    }

    public static int getCursorByEvent(TextView textBox, MotionEvent event, boolean eventFromParent) {
        return getCursorByEvent(textBox, event.getX(), event.getY(), eventFromParent);
    }

    public static int getCursorByEvent(TextView textBox, float eventX, float eventY, boolean eventFromParent) {
        if (textBox == null) {
            return 0;
        }

        Layout layout = textBox.getLayout();

        if (layout != null) {
            return getCursorByPosition(textBox, layout, eventX, eventY, eventFromParent);
        }

        return 0;
    }


    private static int getCursorByPosition(TextView textBox, Layout layout, float eventX, float eventY, boolean eventFromParent) {
        int offset;

        eventX = eventX - (eventFromParent ? textBox.getX() : 0);
        eventY = eventY - (eventFromParent ? textBox.getY() : 0);


//        if (textBox.getRotation()%360.0f!=0.0f) {
        if (eventFromParent) {
//            Matrix mat = new Matrix();
            if (mat==null) {
                mat = new Matrix();
            }
            mat.reset();
            float totalDegree = textBox.getRotation();
            mat.setRotate(-totalDegree, textBox.getWidth() / 2, textBox.getHeight() / 2);
            float pts[] = {eventX, eventY};
            mat.mapPoints(pts);
            eventX = pts[0];
            eventY = pts[1];
        }

        float x = eventX + textBox.getScrollX() - textBox.getPaddingStart();
        float y = eventY + textBox.getScrollY() - textBox.getPaddingTop();

        int line = layout.getLineForVertical((int) y);

        offset = layout.getOffsetForHorizontal(line, x);

        if (offset >= 0 && offset <= textBox.getText().length()) {
        } else {
            if (offset < 0) {
                offset = 0;
            } else {
                offset = textBox.getText().length();
            }
        }

        return offset;
    }

//    public static int getPreciseOffset(TextView textView, int x, int y) {
//        Layout layout = textView.getLayout();
//
//        if (layout != null) {
//            int topVisibleLine = layout.getLineForVertical(y);
//            int offset = layout.getOffsetForHorizontal(topVisibleLine, x);
//
//            int offsetX = (int) layout.getPrimaryHorizontal(offset);
//
//            if (offsetX > x) {
//                return layout.getOffsetToLeftOf(offset);
//            } else {
//                return offset;
//            }
//        } else {
//            return -1;
//        }
//
//
//    }

//    public static int getHysteresisOffset(TextView textView, int x, int y, int previousOffset) {
//        final Layout layout = textView.getLayout();
//        if (layout == null) return -1;
//
//        int line = layout.getLineForVertical(y);
//
//        // The "HACK BLOCK"S in this function is required because of how Android Layout for
//        // TextView works - if 'offset' equals to the last character of a line, then
//        //
//        // * getLineForOffset(offset) will result the NEXT line
//        // * getPrimaryHorizontal(offset) will return 0 because the next insertion point is on the next line
//        // * getOffsetForHorizontal(line, x) will not return the last offset of a line no matter where x is
//        // These are highly undesired and is worked around with the HACK BLOCK
//        //
//        // @see Moon+ Reader/Color Note - see how it can't select the last character of a line unless you move
//        // the cursor to the beginning of the next line.
//        //
//        ////////////////////HACK BLOCK////////////////////////////////////////////////////
//
//        if (isEndOfLineOffset(layout, previousOffset)) {
//            // we have to minus one from the offset so that the code below to find
//            // the previous line can work correctly.
//            int left = (int) layout.getPrimaryHorizontal(previousOffset - 1);
//            int right = (int) layout.getLineRight(line);
//            int threshold = (right - left) / 2; // half the width of the last character
//            if (x > right - threshold) {
//                previousOffset -= 1;
//            }
//        }
//        ///////////////////////////////////////////////////////////////////////////////////
//
//        final int previousLine = layout.getLineForOffset(previousOffset);
//        final int previousLineTop = layout.getLineTop(previousLine);
//        final int previousLineBottom = layout.getLineBottom(previousLine);
//        final int hysteresisThreshold = (previousLineBottom - previousLineTop) / 2;
//
//        // If new line is just before or after previous line and y position is less than
//        // hysteresisThreshold away from previous line, keep cursor on previous line.
//        if (((line == previousLine + 1) && ((y - previousLineBottom) < hysteresisThreshold)) || ((line == previousLine - 1) && ((
//                previousLineTop
//                        - y) < hysteresisThreshold))) {
//            line = previousLine;
//        }
//
//        int offset = layout.getOffsetForHorizontal(line, x);
//
//        // This allow the user to select the last character of a line without moving the
//        // cursor to the next line. (As Layout.getOffsetForHorizontal does not return the
//        // offset of the last character of the specified line)
//        //
//        // But this function will probably get called again immediately, must decrement the offset
//        // by 1 to compensate for the change made below. (see previous HACK BLOCK)
//        /////////////////////HACK BLOCK///////////////////////////////////////////////////
//        if (offset < textView.getText().length() - 1) {
//            if (isEndOfLineOffset(layout, offset + 1)) {
//                int left = (int) layout.getPrimaryHorizontal(offset);
//                int right = (int) layout.getLineRight(line);
//                int threshold = (right - left) / 2; // half the width of the last character
//                if (x > right - threshold) {
//                    offset += 1;
//                }
//            }
//        }
//        //////////////////////////////////////////////////////////////////////////////////
//
//        return offset;
//    }
//
//    private static boolean isEndOfLineOffset(Layout layout, int offset) {
//        return offset > 0 && layout.getLineForOffset(offset) == layout.getLineForOffset(offset - 1) + 1;
//    }

    public static int dp2px(Context context, float dpValue) {
        final float scale = context.getResources().getDisplayMetrics().density;
        return (int) (dpValue * scale + 0.5f);
    }

    public static float convertDpToPixel(float dp, Context context){
        return dp * getDensity(context);
    }

    public static float getDensity(Context context){
        DisplayMetrics metrics = context.getResources().getDisplayMetrics();
        return metrics.density;
    }

    // https://stackoverflow.com/questions/1109022/close-hide-the-android-soft-keyboard?rq=1
    public static void hideSoftKeyboard(Activity activity) {
        InputMethodManager imm = (InputMethodManager) activity.getSystemService(Activity.INPUT_METHOD_SERVICE);
        //Find the currently focused view, so we can grab the correct window token from it.
        View view = activity.getCurrentFocus();
        //If no view currently has focus, create a new one, just so we can grab a window token from it
        if (view == null) {
            // TODO : check if there is  a memory issue about creating view repeatedly.
            view = new View(activity);
        }
        imm.hideSoftInputFromWindow(view.getWindowToken(), 0);
    }

//    public static Rect getWidthOfString(TextView v, String str) {
//        Rect bounds = new Rect();
//        Paint textPaint = v.getPaint();
//        textPaint.getTextBounds(str, 0, str.length(), bounds);
//
//        return bounds;
//    }

    public static float getHeightOfString(TextView v, String str) {
        Rect bounds = new Rect();
        Paint textPaint = v.getPaint();
        textPaint.getTextBounds(str, 0, str.length(), bounds);

        return bounds.height();
    }

    public static float getHeightOfString(TextPaint paint, String s) {
        if (rect == null) {
            rect = new Rect();
        }
        paint.getTextBounds(s, 0, s.length(), rect);

        return rect.height();
    }

    public static float getWidthOfString(TextView v, String str) {
        TextPaint textPaint = v.getPaint();
        return StaticLayout.getDesiredWidth(str, textPaint);
//        Paint textPaint = v.getPaint();
//        return textPaint.measureText(str);

    }

    public static void showSoftKeyboard(Activity activity) {
        InputMethodManager imm = (InputMethodManager) activity.getSystemService(Activity.INPUT_METHOD_SERVICE);
        imm.toggleSoftInput(InputMethodManager.SHOW_IMPLICIT, 0);
    }

    public static int getTextHeight(int deviceWidth, TextView textBox) {
        return getTextHeight(deviceWidth, 0, textBox);
    }

    public static int getTextHeight(int deviceWidth, int deviceHeight, TextView textBox) {
//        TextView textView = new TextView(textBox.getContext());
//        textView.setText(text);
//        textView.setTextSize(TypedValue.COMPLEX_UNIT_PX, textSize);
        int widthMeasureSpec = View.MeasureSpec.makeMeasureSpec(deviceWidth, View.MeasureSpec.AT_MOST);
//        int heightMeasureSpec = View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED);
        int heightMeasureSpec = View.MeasureSpec.makeMeasureSpec(deviceHeight, View.MeasureSpec.UNSPECIFIED);
        textBox.measure(widthMeasureSpec, heightMeasureSpec);
        return textBox.getMeasuredHeight();
    }

}
